//////////////////////////////////////////////
// Mesh.h
//
//////////////////////////////////////////////

/// Defines / Macros -------------------------

#pragma once

/// Includes ---------------------------------

// nkGraphics
#include "../Bounds/BoundingBox.h"

#include "../Dll/DllDefines.h"

#include "../Resources/Resource.h"

#include "Enums/IndexFormat.h"
#include "Enums/PrimitiveTopology.h"

#include "InputLayouts/MeshInputLayout.h"

// nkExport
#include <NilkinsExport/Exportable/Exportable.h>

// nkMemory
#include <NilkinsMemory/Containers/Buffer.h>
#include <NilkinsMemory/Containers/BufferView.h>

#include <NilkinsMemory/Pointers/UniquePtr.h>

/// Class ------------------------------------
	
namespace nkGraphics
{
	class DLL_GRAPHICS_EXPORT Mesh : public Resource, public nkExport::Exportable
	{		
		public :
		
			// Destructor
			virtual ~Mesh () ;

			// Getters
			const BoundingBox& getBounds () const ;
			nkMemory::BufferView<unsigned char> getVertexBuffer (unsigned int index) const ;
			unsigned int getVertexBufferStride (unsigned int index) const ;
			unsigned int getVertexBufferCount () const ;
			nkMemory::BufferView<unsigned char> getIndexBuffer () const ;
			const MeshInputLayout& getInputLayout () const ;
			unsigned int getId () const ;
			unsigned int getVertexCount () const ;
			unsigned int getIndexCount () const ;
			PRIMITIVE_TOPOLOGY getTopology () const ;
			INDEX_FORMAT getIndexFormat () const ;
			bool getAutoComputeBounds () const ;

			// Setters
			void setBounds (const BoundingBox& value) ;
			void addVertexBuffer (nkMemory::BufferView<unsigned char> view, unsigned int stride = 0) ;
			void addVertexBufferCopy (nkMemory::BufferView<unsigned char> view, unsigned int stride = 0) ;
			void addVertexBufferForward (nkMemory::Buffer&& buffer, unsigned int stride = 0) ;
			void removeVertexBuffer(unsigned int index) ;
			void setIndexBuffer (nkMemory::BufferView<unsigned char> view) ;
			void setIndexBufferCopy (nkMemory::BufferView<unsigned char> view) ;
			void setIndexBufferForward (nkMemory::Buffer&& buffer) ;
			void setInputLayout (const MeshInputLayout& layout) ;
			void setId (unsigned int value) ;
			void setVertexCount (int value) ;
			void setIndexCount (int value) ;
			void setTopology (PRIMITIVE_TOPOLOGY value) ;
			void setIndexFormat (INDEX_FORMAT value) ;
			void setAutoComputeBounds (bool value) ;

			// Init
			void computeBounds (nkMemory::StringView positionAttributeName) ;

			// Loading
			virtual bool load () override ;

			// Memory freeing
			virtual void freeShadowBuffers () ;

			// Import / Export
			virtual void exportClassToTree (nkExport::Node* rootNode) override ;
			virtual void importClassFromTree (nkExport::Node* rootNode) override ;

		public :

			// Statics
			static nkMemory::UniquePtr<Mesh> create (System* system = nullptr) ;

		protected :

			// Structures
			struct VertexBufferEntry
			{
				// Data
				nkMemory::Buffer _buffer ;
				nkMemory::BufferView<unsigned char> _view ;

				// Buffer info
				unsigned int _stride ;

				// Flag for quick checks
				bool _isView ;
			} ;

			struct IndexBufferEntry
			{
				// Data
				nkMemory::Buffer _buffer ;
				nkMemory::BufferView<unsigned char> _view ;

				// Flag for quick checks
				bool _isView ;
			} ;

		protected :

			// Functions
			// Constructor
			Mesh (System* system) noexcept ;

			// Layout computing
			unsigned int _getBufferStride (const Mesh::VertexBufferEntry& bufferEntry, unsigned int slot, const MeshInputLayout& layout) const ;
			unsigned int _getAttributeOffset (const MeshInputLayout& layout, unsigned int index) const ;

		protected :
		
			// Attributs
			// Bounds
			BoundingBox _bounds ;

			// Data buffers
			std::vector<VertexBufferEntry> _vertexBuffers ;
			IndexBufferEntry _indexBuffer ;

			// Layout
			MeshInputLayout _inputLayout ;
			MeshInputLayout _lastActiveInputLayout ;

			// Id
			unsigned int _id ;

			// Counts
			unsigned int _vertexCount ;
			unsigned int _indexCount ;

			// Topology to use
			PRIMITIVE_TOPOLOGY _topology ;
			// Format of indices
			INDEX_FORMAT _indexFormat ;

			// Flags
			bool _pathPreImported ;
			bool _autoComputeBounds ;
	} ;
}